using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using XNAGameEngine.GameState;
using XNAGameEngine.Logs;

namespace XNAGameEngine
{
    public sealed class GameEngine : Game
    {
        #region static fields

        /// <summary>
        /// spritebatch used to render to screen
        /// </summary>
        private static SpriteBatch _spritebatch;

        /// <summary>
        /// static access to the services container
        /// </summary>
        private static GameServiceContainer _services;

        /// <summary>
        /// static access to the components collection
        /// </summary>
        private static GameComponentCollection _components;

        /// <summary>
        /// static access to the content manager
        /// </summary>
        private static ContentManager _content;

        /// <summary>
        /// static access to the graphics device manager
        /// </summary>
        private static GraphicsDeviceManager _graphicsDeviceManager;

        #endregion

        #region static properties

        /// <summary>
        /// Provides static access to the SpriteBatch
        /// </summary>
        public static SpriteBatch SpriteBatch
        { get { return _spritebatch; } }

        /// <summary>
        /// Provides static access to the GameServiceContainer
        /// </summary>
        public static GameServiceContainer GameServices
        { get { return _services; } }

        /// <summary>
        /// Provides static access to the GameComponentsCollection
        /// </summary>
        public static GameComponentCollection GameComponents
        { get { return _components; } }

        /// <summary>
        /// Provides static access to the ContentManager
        /// </summary>
        public static ContentManager GameContent
        { get { return _content; } }

        /// <summary>
        /// Provides static access to the GraphicsDeviceManager
        /// </summary>
        public static GraphicsDeviceManager GraphicsDeviceManager
        { get { return _graphicsDeviceManager; } }

        #endregion

        #region constructors

        /// <summary>
        /// Constructor to initialize all local members
        /// </summary>
        public GameEngine() 
            : base()
        {
            _services = Services;
            _content = Content;
            _components = Components;
            _graphicsDeviceManager = new GraphicsDeviceManager(this);
            new ManagerGameState(this);
        }

        #endregion

        #region local methods

        /// <summary>
        /// Initialize the game engine
        /// </summary>
        protected override void Initialize()
        {
            _spritebatch = new SpriteBatch(GraphicsDevice);
            base.Initialize();
        }

        /// <summary>
        /// Registers a GameStateObject object type with a string value. The first state registered
        /// will automatically be assigned to the intial state. This can be changed with the
        /// "SetInitialState() call"
        /// </summary>
        /// <param name="key">the string to register with the object type</param>
        /// <param name="value">the object type to register with the string</param>
        public void RegisterObject(string key, Type objectType)
        {
            //register the game state object
            if (objectType.IsSubclassOf(typeof(GameState.ManagerGameState)))
            {
                GetService<IManagerGameState>().RegisterGameState(key, objectType);
                return;
            }

            //register the game state transition
            if (objectType.IsSubclassOf(typeof(GameStateTransition)))
            {
                GetService<IManagerGameState>().RegisterGameStateTransition(key, objectType);
                return;
            }
        }

        /// <summary>
        /// Set the state the game loads when started up and reset
        /// </summary>
        /// <param name="key">the string value registered to the intial state</param>
        public void SetInitialState(string key)
        {
            GetService<IManagerGameState>().SetInitialState(key);
        }

        #endregion

        #region static methods

        /// <summary>
        /// <para>Provides simple access for getting services. The returned service
        /// is already casted to its type.</para>
        /// <para>EXAMPLE: GameEngine.GetService<IManagerInput>()</para>
        /// </summary>
        /// <typeparam name="T">the type of service to return</typeparam>
        /// <returns>the service specified in the type parameter</returns>
        public static T GetService<T>()
        {
            return (T)_services.GetService(typeof(T));
        }

        #endregion
    }
}
